#include "include.h"
#include "gui/graphicview.h"

#include "compile/debug_memoryleaks"

using namespace model;
using namespace gui;

GraphicView::GraphicView()
: painter(NULL), elementpainter(NULL),helperpainter(NULL), document(NULL), grid(*this)
{
    //ctor
    factor = Vector(1.0,1.0);
    offsetX = 0;
    offsetY = 0;

}

GraphicView::~GraphicView()
{
    //dtor
    setPainter(NULL);
}

void GraphicView::setDocumentRoot(app::Root* documentRoot)
{
	this->document = documentRoot;
	this->onUpdateDocumentRoot();
}

Model* GraphicView::getModel()
{
    if (document)
    {
        return & (document->getModel());
    }
    return  NULL;
}

//////////////////////////////////////////////////////

void GraphicView::paintAll()
{
    this->paintHelpers();
    this->paintModel();
}

void GraphicView::paintModel()
{
    Model * model = this->getModel();
    if (model && elementpainter)
    {
        elementpainter->paint(model);

    }
}


void GraphicView::paintHelpers()
{
    app::Root* root = this->getDocumentRoot();
    if (root && helperpainter)
    {
        if (root->isGridEnabled())
        {
            helperpainter->paint(&grid);
        }

//        PivotHelper* pivot = NULL;
//        helperpainter->paint(pivot);

        //TODO...other helpers
    }
}

////////////////////////////////////////////////////////////////////////


void GraphicView::setPainter(GraphicPainter* painter)
{
    if(elementpainter)
    {
        delete elementpainter;
        elementpainter = NULL;
    }

    if(helperpainter)
    {
        delete helperpainter;
        helperpainter = NULL;
    }
	this->painter = painter;
	if (painter)
	{
		this->elementpainter = new ElementPainter(painter);
		this->helperpainter = new HelperPainter(painter);
	}
}


void GraphicView::rebuildView()
{
    app::Root* root = this->getDocumentRoot();
    if (root && root->isGridEnabled())
    {
        grid.rebuild();
    }
}



void GraphicView::onUpdateDocumentRoot()
{
    rebuildView();
}


///////////////////////////////////////////////////////////
/*
* event handlers
*/

void GraphicView::onResizeEvent(const SizeEvent& sizeevent)
{
    std::cout<<sizeevent<<std::endl;
    rebuildView();
}


void GraphicView::onMouseEvent(const MouseEvent& mouseevent)
{
    std::cout<<mouseevent<<std::endl;
}

///////////////////////////////////////////////////////////







/**
 * Translates a vector in real coordinates to a vector in screen coordinates.
 */
Vector GraphicView::toGui(Vector v)
{
    return Vector(toGuiX(v.x), toGuiY(v.y), 0.0);
}



/**
 * Translates a real coordinate in X to a screen coordinate X.
 * @param visible Pointer to a boolean which will contain true
 * after the call if the coordinate is within the visible range.
 */
double GraphicView::toGuiX(double x, bool* visible)
{
    if (visible!=NULL)
    {
        double res = x*factor.x+offsetX;
        if (res>0.0 && res<getWidth()) {
            *visible = true;
        } else {
            *visible = false;
        }
    }
    return x*factor.x + offsetX;
}



/**
 * Translates a real coordinate in Y to a screen coordinate Y.
 */
double GraphicView::toGuiY(double y)
{
    return -y*factor.y + getHeight() - offsetY;
}



/**
 * Translates a real coordinate distance to a screen coordinate distance.
 */
double GraphicView::toGuiDX(double d)
{
    return d*factor.x;
}



/**
 * Translates a real coordinate distance to a screen coordinate distance.
 */
double GraphicView::toGuiDY(double d)
{
    return d*factor.y;
}



/**
 * Translates a vector in screen coordinates to a vector in real coordinates.
 */
Vector GraphicView::toGraph(Vector v)
{
    return Vector(toGraphX(Math::round(v.x)),
                     toGraphY(Math::round(v.y)), 0.0);
}



/**
 * Translates two screen coordinates to a vector in real coordinates.
 */
Vector GraphicView::toGraph(int x, int y)
{
    return Vector(toGraphX(x), toGraphY(y), 0.0);
}


/**
 * Translates a screen coordinate in X to a real coordinate X.
 */
double GraphicView::toGraphX(int x)
{
    return (x - offsetX)/factor.x;
}



/**
 * Translates a screen coordinate in Y to a real coordinate Y.
 */
double GraphicView::toGraphY(int y)
{
    return -(y - getHeight() + offsetY)/factor.y;
}



/**
 * Translates a screen coordinate distance to a real coordinate distance.
 */
double GraphicView::toGraphDX(int d)
{
    return d/factor.x;
}



/**
 * Translates a screen coordinate distance to a real coordinate distance.
 */
double GraphicView::toGraphDY(int d)
{
    return d/factor.y;
}





/**
 * Sets the zoom factor in X for this visualization of the graphic.
 */
void GraphicView::setFactorX(double f)
{
//    if (!zoomFrozen)
    {
        factor.x = fabs(f);
    }
}



/**
 * Sets the zoom factor in Y for this visualization of the graphic.
 */
void GraphicView::setFactorY(double f)
{
//    if (!zoomFrozen)
    {
        factor.y = fabs(f);
    }
}

